--- busybox-1.20.2/findutils/grep.c	2012-06-26 15:35:45.000000000 +0200
+++ busybox-git/findutils/grep.c	2014-11-17 17:25:46.814511033 +0100
@@ -344,11 +344,42 @@
 		while (pattern_ptr) {
 			gl = (grep_list_data_t *)pattern_ptr->data;
 			if (FGREP_FLAG) {
-				found |= (((option_mask32 & OPT_i)
-					? strcasestr(line, gl->pattern)
-					: strstr(line, gl->pattern)
-					) != NULL);
+				char *match;
+				char *str = line;
+ opt_f_again:
+				match = ((option_mask32 & OPT_i)
+					? strcasestr(str, gl->pattern)
+					: strstr(str, gl->pattern)
+					);
+				if (match) {
+					if (option_mask32 & OPT_x) {
+						if (match != str)
+							goto opt_f_not_found;
+						if (str[strlen(gl->pattern)] != '\0')
+							goto opt_f_not_found;
+					} else
+					if (option_mask32 & OPT_w) {
+						char c = (match != str) ? match[-1] : ' ';
+						if (!isalnum(c) && c != '_') {
+							c = match[strlen(gl->pattern)];
+							if (!c || (!isalnum(c) && c != '_'))
+								goto opt_f_found;
+						}
+						str = match + 1;
+						goto opt_f_again;
+					}
+ opt_f_found:
+					found = 1;
+ opt_f_not_found: ;
+				}
 			} else {
+#if ENABLE_EXTRA_COMPAT
+				unsigned start_pos;
+#else
+				int match_flg;
+#endif
+				char *match_at;
+
 				if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
 					gl->flg_mem_alocated_compiled |= COMPILED;
 #if !ENABLE_EXTRA_COMPAT
@@ -363,29 +394,58 @@
 #if !ENABLE_EXTRA_COMPAT
 				gl->matched_range.rm_so = 0;
 				gl->matched_range.rm_eo = 0;
+				match_flg = 0;
+#else
+				start_pos = 0;
 #endif
+				match_at = line;
+ opt_w_again:
+//bb_error_msg("'%s' start_pos:%d line_len:%d", match_at, start_pos, line_len);
 				if (
 #if !ENABLE_EXTRA_COMPAT
-					regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0
+					regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, match_flg) == 0
 #else
-					re_search(&gl->compiled_regex, line, line_len,
-							/*start:*/ 0, /*range:*/ line_len,
+					re_search(&gl->compiled_regex, match_at, line_len,
+							start_pos, /*range:*/ line_len,
 							&gl->matched_range) >= 0
 #endif
 				) {
 					if (option_mask32 & OPT_x) {
 						found = (gl->matched_range.rm_so == 0
-						         && line[gl->matched_range.rm_eo] == '\0');
-					} else if (!(option_mask32 & OPT_w)) {
+						         && match_at[gl->matched_range.rm_eo] == '\0');
+					} else
+					if (!(option_mask32 & OPT_w)) {
 						found = 1;
 					} else {
 						char c = ' ';
-						if (gl->matched_range.rm_so)
-							c = line[gl->matched_range.rm_so - 1];
+						if (match_at > line || gl->matched_range.rm_so != 0) {
+							c = match_at[gl->matched_range.rm_so - 1];
+						}
 						if (!isalnum(c) && c != '_') {
-							c = line[gl->matched_range.rm_eo];
-							if (!c || (!isalnum(c) && c != '_'))
-								found = 1;
+							c = match_at[gl->matched_range.rm_eo];
+						}
+						if (!isalnum(c) && c != '_') {
+							found = 1;
+						} else {
+			/*
+			 * Why check gl->matched_range.rm_eo?
+			 * Zero-length match makes -w skip the line:
+			 * "echo foo | grep ^" prints "foo",
+			 * "echo foo | grep -w ^" prints nothing.
+			 * Without such check, we can loop forever.
+			 */
+#if !ENABLE_EXTRA_COMPAT
+							if (gl->matched_range.rm_eo != 0) {
+								match_at += gl->matched_range.rm_eo;
+								match_flg |= REG_NOTBOL;
+								goto opt_w_again;
+							}
+#else
+							if (gl->matched_range.rm_eo > start_pos) {
+								start_pos = gl->matched_range.rm_eo;
+								goto opt_w_again;
+							}
+#endif
 						}
 					}
 				}
@@ -608,7 +668,7 @@
 	int matched = 0;
 	recursive_action(dir,
 		/* recurse=yes */ ACTION_RECURSE |
-		/* followLinks=no */
+		/* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 |
 		/* depthFirst=yes */ ACTION_DEPTHFIRST,
 		/* fileAction= */ file_action_grep,
 		/* dirAction= */ NULL,
@@ -638,7 +698,7 @@
 
 	if (opts & OPT_C) {
 		/* -C unsets prev -A and -B, but following -A or -B
-		   may override it */
+		 * may override it */
 		if (!(opts & OPT_A)) /* not overridden */
 			lines_after = Copt;
 		if (!(opts & OPT_B)) /* not overridden */
@@ -683,7 +743,7 @@
 		option_mask32 |= OPT_F;
 
 #if !ENABLE_EXTRA_COMPAT
-	if (!(option_mask32 & (OPT_o | OPT_w)))
+	if (!(option_mask32 & (OPT_o | OPT_w | OPT_x)))
 		reflags = REG_NOSUB;
 #endif
 
